<?php

namespace WeForge\Queue;

use HttpClient\Aliyun\ServerlessWorkflow\Application as Fnf;
use HttpClient\RequestException;
use Illuminate\Contracts\Queue\Queue as QueueContract;
use Illuminate\Queue\Queue;
use RuntimeException;

class FnfQueue extends Queue implements QueueContract
{
    /**
     * @var \HttpClient\Aliyun\ServerlessWorkflow\Application
     */
    protected $fnf;

    /**
     * The name of the workflow.
     *
     * @var string
     */
    protected $flow;

    /**
     * Create a new MnsQueue instance.
     *
     * @param \HttpClient\Aliyun\ServerlessWorkflow\Application $fnf
     * @param string $flow
     */
    public function __construct(Fnf $fnf, $flow)
    {
        $this->fnf = $fnf;
        $this->flow = $flow;
    }

    /**
     * Get the size of the queue.
     *
     * @param  string|null  $queue
     * @return int
     */
    public function size($queue = null)
    {
        throw new RuntimeException('The operation is not supported on the FNF queue');
    }

    /**
     * Push a new job onto the queue.
     *
     * @param  string|object  $job
     * @param  mixed  $data
     * @param  string|null  $queue
     * @return mixed
     */
    public function push($job, $data = '', $queue = null)
    {
        return $this->pushRaw(
            $this->createPayload($job, $queue, $data),
            $queue
        );
    }

    /**
     * Push a raw payload onto the queue.
     *
     * @param  string  $payload
     * @param  string|null  $queue
     * @param  array  $options
     * @return mixed
     */
    public function pushRaw($payload, $queue = null, array $options = [])
    {
        return $this->startExecution(
            json_encode(['payload' => $payload])
        )['Name'];
    }

    /**
     * Push a new job onto the queue after a delay.
     *
     * @param  \DateTimeInterface|\DateInterval|int  $delay
     * @param  string|object  $job
     * @param  mixed  $data
     * @param  string|null  $queue
     * @return mixed
     */
    public function later($delay, $job, $data = '', $queue = null)
    {
        return $this->startExecution(
            json_encode(['payload' => $this->createPayload($job, $queue, $data)]),
            $this->secondsUntil($delay)
        )['Name'];
    }

    /**
     * Pop the next job off of the queue.
     *
     * @param  string  $queue
     * @return \Illuminate\Contracts\Queue\Job|null
     */
    public function pop($queue = null)
    {
        throw new RuntimeException('The operation is not supported on the FNF queue');
    }

    /**
     * Release a job back onto the queue.
     *
     * @param  string  $queue
     * @param  array  $job
     * @param  int  $delay
     *
     * @return \HttpClient\Response
     */
    public function release($queue, $job, $delay)
    {
        return $this->startExecution(json_encode($job), $delay);
    }

    /**
     * Execute a job.
     *
     * @param  string  $message
     * @param  int $wait
     *
     * @return \HttpClient\Response
     */
    protected function startExecution($message, $wait = 0)
    {
        return $this->fnf->execution->start($this->flow, [
            'Input' => json_encode([
                'wait' => (int) $wait,
                'payload' => json_encode([
                    'cli' => sprintf('php artisan weforge:work fnf %s', base64_encode($message)),
                ]),
            ]),
        ]);
    }
}
